/*
    SDL - Simple DirectMedia Layer
    Partial implementation of SDL library (originally written by
    Sam Lantinga <slouken@libsdl.org>) for the particular purpose to support
    Prequengine (http://code.google.com/p/prequengine/) on BlackBerry(tm)
    tablets and smartphones.

    Copyright (C) 2013  xlamsp

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

    xlamsp@gmail.com
*/

#include "SDL.h"
#include "SDL_sysvideo.h"


extern int SDL_StartEventLoop(Uint32 flags);
extern void SDL_StopEventLoop(void);

/* Available video drivers */
static VideoBootStrap *bootstrap[] = {
    &BB_bootstrap,
    NULL
};

SDL_VideoDevice *current_video = NULL;

int SDL_VideoInit(const char *driver_name, Uint32 flags)
{
    SDL_VideoDevice *video;
    int index;
    int i;
    SDL_PixelFormat vformat;

    SDL_Log(DEBUG1, "entered");

    /* Check to make sure we don't overwrite 'current_video' */
    if(current_video != NULL) {
        SDL_VideoQuit();
    }

    /* Select the proper video driver */
    index = 0;
    video = NULL;
    if(driver_name != NULL) {
        for(i = 0; bootstrap[i]; i++) {
            if(SDL_strcasecmp(bootstrap[i]->name, driver_name) == 0) {
                if(bootstrap[i]->available()) {
                    video = bootstrap[i]->create(index);
                    break;
                }
            }
        }
    } else {
        for(i = 0; bootstrap[i]; i++) {
            if(bootstrap[i]->available()) {
                video = bootstrap[i]->create(index);
                if(video != NULL) {
                    break;
                }
            }
        }
    }

    if(video == NULL) {
        SDL_Log(ERROR, "No available video device");
        return -1;
    }

    current_video = video;
    current_video->name = bootstrap[i]->name;

    /* Do some basic variable initialization */
    video->screen = NULL;

    /* Initialize the video subsystem */
    SDL_memset(&vformat, 0, sizeof(vformat));
    if(video->VideoInit(video, &vformat) < 0) {
        SDL_Log(ERROR, "VideoInit() failed");
        SDL_VideoQuit();
        return -1;
    }

    /* Start the event loop */
    if(SDL_StartEventLoop(flags) < 0) {
        SDL_VideoQuit();
        return -1;
    }

    return 0;
}

void SDL_VideoQuit (void)
{
    SDL_Log(DEBUG1, "entered, current_video=0x%p", current_video);

    if(current_video) {
        SDL_VideoDevice *video = current_video;

        /* Halt event processing before doing anything else */
        SDL_StopEventLoop();

        /* Clean up the system video */
        video->VideoQuit(video);

        /* Finish cleaning up video subsystem */
        video->free(video);
        current_video = NULL;
    }
}

SDL_Surface * SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags)
{
    SDL_VideoDevice *video;

    SDL_Log(DEBUG1, "width=%d height=%d bpp=%d flags=0x%x", width, height, bpp, flags);

    /* Start up the video driver, if necessary..
       WARNING: This is the only function protected this way!
     */
    if(!current_video) {
        if(SDL_Init(SDL_INIT_VIDEO) < 0) {
            SDL_Log(ERROR, "failed to init video subsystem");
            return NULL;
        }
    }
    video = current_video;

    /* Default to the current width and height */
    if(width == 0) {
        width = video->info.current_w;
    }
    if(height == 0) {
        height = video->info.current_h;
    }

    SDL_VideoSurface = video->SetVideoMode(video, SDL_VideoSurface, width, height, bpp, flags);

    if(!SDL_VideoSurface) {
        SDL_Log(ERROR, "failed");
    }

    return SDL_VideoSurface;
}

void SDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h)
{
    if(screen) {
        SDL_Rect rect;

        /* Perform some checking */
        if(w == 0) {
            w = screen->w;
        }
        if(h == 0) {
            h = screen->h;
        }
        if((int)(x + w) > screen->w) {
            return;
        }
        if((int)(y + h) > screen->h) {
            return;
        }

        /* Fill the rectangle */
        rect.x = (Sint16)x;
        rect.y = (Sint16)y;
        rect.w = (Uint16)w;
        rect.h = (Uint16)h;
        SDL_UpdateRects(screen, 1, &rect);
    }
}

void SDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects)
{
    SDL_VideoDevice *video = current_video;

    if(screen == SDL_VideoSurface) {
        video->UpdateRects(video, numrects, rects);
    }
}

int SDL_SetPalette(SDL_Surface *screen, int which, SDL_Color *colors, int firstcolor, int ncolors)
{
    SDL_Log(DEBUG2, "screen=0x%p which=0x%x colors=0x%p firstcolor=%d ncolors=%d",
        screen, which, colors, firstcolor, ncolors);

    if(screen == NULL || colors == NULL || firstcolor < 0 || ncolors <= 0) {
        SDL_Log(ERROR, "invalid parameters!");
        return 0;
    }

    if(!(screen->format->palette) || screen->format->palette->ncolors <= firstcolor) {
        SDL_Log(ERROR, "bad parameters!");
        return 0;
    }

    if(firstcolor + ncolors > screen->format->palette->ncolors) {
        ncolors = screen->format->palette->ncolors - firstcolor;
    }

    SDL_memcpy(screen->format->palette->colors + firstcolor, colors, ncolors * sizeof(SDL_Color));

    /*
    if(SDL_PHYSPAL) {
        update full screen
    }
    */

    return 1;
}

int SDL_SetColors(SDL_Surface *screen, SDL_Color *colors, int firstcolor, int ncolors)
{
    SDL_Log(DEBUG2, "screen=0x%p colors=0x%p firstcolor=%d ncolors=%d",
        screen, colors, firstcolor, ncolors);

    return SDL_SetPalette(screen, SDL_LOGPAL | SDL_PHYSPAL, colors, firstcolor, ncolors);
}

void SDL_WM_SetCaption(const char *title, const char *icon)
{
    /* Not applicable */
    return;
}

